package com.xbongbong.pay.platform.unionpay.utils;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.UnsupportedEncodingException;
import java.security.KeyStore;
import java.security.MessageDigest;
import java.security.PrivateKey;
import java.security.Signature;
import java.util.Base64;

/**
 *
 * @author 魏荣杰
 * @date 2021/1/20 09:30
 * @since
 * @version
 */
public class UnionPaySecureUtil {
    private static final Logger LOG = LoggerFactory.getLogger(UnionPaySecureUtil.class);

    /**
     * 算法常量： SHA256
     */
    private static final String ALGORITHM_SHA256 = "SHA-256";
    /**
     * 算法常量：SHA256withRSA
     */
    private static final String BC_PROV_ALGORITHM_SHA256RSA = "SHA256withRSA";

    /**
     * sha256计算后进行16进制转换
     *
     * @param data
     *            待计算的数据
     * @param encoding
     *            编码
     * @return 计算结果
     */
    public static String sha256X16Str(String data, String encoding) {
        byte[] bytes = sha256(data, encoding);
        StringBuilder sha256StrBuff = new StringBuilder();
        for (int i = 0; i < bytes.length; i++) {
            if (Integer.toHexString(0xFF & bytes[i]).length() == 1) {
                sha256StrBuff.append("0").append(
                        Integer.toHexString(0xFF & bytes[i]));
            } else {
                sha256StrBuff.append(Integer.toHexString(0xFF & bytes[i]));
            }
        }
        return sha256StrBuff.toString();
    }

    /**
     * sha256计算后进行16进制转换
     *
     * @param data
     *            待计算的数据
     * @param encoding
     *            编码
     * @return 计算结果
     */
    public static byte[] sha256X16(String data, String encoding) {
        try {
            return sha256X16Str(data, encoding).getBytes(encoding);
        } catch (UnsupportedEncodingException e) {
            return null;
        }
    }

    /**
     * sha256计算
     *
     * @param data
     *            待计算的数据
     * @param encoding
     *            字符集编码
     * @return
     */
    private static byte[] sha256(String data, String encoding) {
        try {
            return sha256(data.getBytes(encoding));
        } catch (UnsupportedEncodingException e) {
            LOG.error("SHA256计算失败", e);
            return null;
        }
    }

    /**
     * sha256计算.
     *
     * @param data
     *            待计算的数据
     * @return 计算结果
     */
    private static byte[] sha256(byte[] data) {
        MessageDigest md = null;
        try {
            md = MessageDigest.getInstance(ALGORITHM_SHA256);
            md.reset();
            md.update(data);
            return md.digest();
        } catch (Exception e) {
            LOG.error("SHA256计算失败", e);
            return null;
        }
    }

    /**
     * @param privateKey
     * @param data
     * @return
     * @throws Exception
     */
    public static byte[] signBySoft256(PrivateKey privateKey, byte[] data) throws Exception {
        byte[] result = null;
//        Signature st = Signature.getInstance(BC_PROV_ALGORITHM_SHA256RSA, "BC");
        Signature st = Signature.getInstance(BC_PROV_ALGORITHM_SHA256RSA);
        st.initSign(privateKey);
        st.update(data);
        result = st.sign();
        return result;
    }


    /**
     * BASE64编码
     *
     * @param inputByte
     *            待编码数据
     * @return 解码后的数据
     */
    public static String base64Encode(byte[] inputByte) {
        return Base64.getEncoder().encodeToString(inputByte);
    }

    public static void main(String[] args) throws Exception {
        String s = "accessType=0&backUrl=http://www.specialUrl.com&bizType=000201&certId=69629715588&channelType=07&currencyCode=156&encoding=UTF-8&frontUrl=https://www.baidu.com&merId=777290058188811&orderId=1611554171276&payTimeout=20210125141111&signMethod=01&txnAmt=1&txnSubType=01&txnTime=20210125135611&txnType=01&version=5.1.0";
        KeyStore keyStore = UnionPayCertUtil.getKeyStore("union/acp_test_sign.pfx", "000000", "PKCS12");
        String s1 = sha256X16Str(s, "utf-8");
        System.out.println(s1);
        PrivateKey signCertPrivateKey = UnionPayCertUtil.getSignCertPrivateKey(keyStore, "000000");
        System.out.println(UnionPaySecureUtil.base64Encode(UnionPaySecureUtil.signBySoft256(signCertPrivateKey, sha256X16(s, "utf-8"))));

    }
}
